/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * @file rw_t1t.c
 * @brief T1T tag implementation
 */

#include "nci_feature.h"
#if IS_FEATURE_ON(NCI_FEATURE_RW_T1T)

#include "rw_tag.h"
#include "nfc_log_api.h"
#include "nci_data.h"
#include "nci_utils.h"
#include "nfc_hex_utils.h"
#include "rw_int.h"

#define T1T_IS_TOPAZ96 0x11
#define T1T_IS_TOPAZ512 0x12

#define T1T_HR_LEN 2
#define T1T_UID_LEN 4
#define T1T_STATIC_CMD_LEN 7
#define T1T_DYNAMIC_CMD_LEN 14
#define T1T_DYNAMIC_DAT_LEN 8
#define T1T_DYNAMIC_LOCK_LEN 6

#define T1T_STATIC_RESERVED_LEN 0x10
#define T1T_DYNAMIC_RESERVED_LEN 0x18

#define T1T_RALL_RSP_LEN 122
#define T1T_READ_RSP_LEN 2
#define T1T_WRITE_E_RSP_LEN 2
#define T1T_WRITE_NE_RSP_LEN 2

#define T1T_RSEG_RSP_LEN 129
#define T1T_READ8_RSP_LEN 9
#define T1T_WRITE_E8_RSP_LEN 9
#define T1T_WRITE_NE8_RSP_LEN 9

#define T1T_SEGMENT_SIZE 0x80
#define T1T_BLOCK_SIZE 8

#define T1T_STATIC_MAX_SIZE 0x78
#define T1T_STATIC_MAX_BLCOK_COUNT 0x0E

#define T1T_CC_OFFSET 8
#define T1T_CC_LEN 4

#define T1T_CC0_NMN_BYTE 0x08
#define T1T_CC1_VNO_BYTE 0x09
#define T1T_CC2_TMS_BYTE 0x0A
#define T1T_CC3_RWA_BYTE 0x0B

#define T1T_STATIC_LOCK_OFFSET 0x70
#define T1T_STATIC_LOCK_LEN 2

#define T1T_STATIC_LOCK_BLOCK 0x0E

#define T1T_MAX_BLOCK_SIZE 0x40

#define T1T_BLOCK_LOCKED 0b1
#define T1T_BLOCK_UNCHECKED 0b0

#define T1T_CMD_RID 0x78
#define T1T_CMD_RALL 0x00
#define T1T_CMD_READ 0x01
#define T1T_CMD_WRITE_E 0x53
#define T1T_CMD_WRITE_NE 0x1A
#define T1T_CMD_RSEG 0x10
#define T1T_CMD_READ8 0x02
#define T1T_CMD_WRITE_E8 0x54
#define T1T_CMD_WRITE_NE8 0x1B

#define T1T_TLV_NULL 0x00
#define T1T_TLV_LOCK 0x01
#define T1T_TLV_MEM 0x02
#define T1T_TLV_NDEF 0x03
#define T1T_TLV_PROP 0xFD
#define T1T_TLV_TERM 0xFE

#define T1T_NDEF_SUPPORED 0x10
#define T1T_CC_READ_ONLY 0x0F
#define T1T_CC_MAGIC_NUM 0xE1
#define T1T_CC_VNO 0x11
#define T1T_CC_RWA_RW 0x00
#define T1T_CC_RWA_RO 0x0F

#define T1T_OFFSET_TO_ADD(_offset) ((((_offset) / T1T_BLOCK_SIZE) << 3) | ((_offset) % T1T_BLOCK_SIZE))

#if IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
/** @brief NDEF Format静态T1T卡片时使用的初始化数据 */
const static uint8_t s_t1t_init_data_static[] = {
    T1T_CC_MAGIC_NUM, T1T_CC_VNO, 0x0E, T1T_CC_RWA_RW, // cc
    T1T_TLV_NDEF, 0x00, // NDEF TLV
    T1T_TLV_TERM, // Terminator TLV
};
/** @brief NDEF Format动态T1T卡片时使用的初始化数据 */
const static uint8_t s_t1t_init_data_dynamic[] = {
    T1T_CC_MAGIC_NUM, T1T_CC_VNO, 0x3F, T1T_CC_RWA_RW, // CC
    T1T_TLV_LOCK, 0x03, 0xF2, 0x30, 0x33, // Lock TLV
    T1T_TLV_MEM, 0x03, 0xF0, 0x02, 0x03,  // Mem TLV
    T1T_TLV_NDEF, 0x00,                   // NDEF TLV
};

const static uint8_t s_t1t_mask_bits[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};

#endif // IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)

/**
 * @brief T1T卡片信息
 */
typedef struct {
    /** @brief 是否执行了NDEF检测 */
    bool is_ndef_detected;
    /** @brief 此T1T卡是否只支持Static内存分布 */
    bool is_static;
    /** @brief 保存T1T卡片的HR信息 */
    uint8_t hr[T1T_HR_LEN];
    /** @brief 保存此卡片的UID信息 */
    uint8_t uid[T1T_UID_LEN];
#if IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
    /** @brief 保存T1T卡片一个segment的内容 */
    uint8_t mem[T1T_SEGMENT_SIZE];
    /** @brief Dynamic Lock Bit起始地址 */
    uint16_t lock_bit_start;
    /** @brief Dynamic Lock Bit数量 */
    uint8_t lock_bits_count;
    /** @brief 保存NDEF Len的第一个byte在T1T Block数据中的偏移量 */
    uint8_t ndef_len_start;
    /** @brief 保存NDEF Value第一个byte在T1T Block数据中的偏移量 */
    uint8_t ndef_value_start;
    /** @brief 记录当前卡片中NDEF Value的长度 */
    uint16_t ndef_len;
    /** @brief 记录当前卡片能写入的NDEF数据最大长度 */
    uint16_t ndef_max_size;
    /** @brief 记录NDEF相关的一些标志位 */
    uint8_t ndef_flags;
    /**
     * @brief 记录T1T Block数据中哪些byte是保留的，不能写入NDEF数据
     *
     * @note 每一个byte对应T1T Block数据中的一个Block
     * @note 每个byte的每一个bit对应Block中的一个byte
     * @note attr bit的值为1时，表示该byte是保留的，不能写入NDEF数据
     * @example attr[1] = 0b00000001, 表示第2个Block的第1个byte是保留的，不能写入NDEF数据，其余byte可以写入NDEF数据
    */
    uint8_t attr[T1T_MAX_BLOCK_SIZE];
    /**
     * @brief 记录T1T Block数据中哪些byte是锁定的，只允许读取不允许写入
     *
     * @note 每一个byte对应T1T Block数据中的一个Block
     * @note 每个byte的每一个bit对应Block中的一个byte
     * @note lock_attr bit的值为1时，表示该byte是只读的，不能写入数据
     * @example lock_attr[1] = 0b00000001, 表示第2个Block的第1个byte是只读的，不能写入数据，其余byte可以写入数据
     */
    uint8_t lock_attr[T1T_MAX_BLOCK_SIZE];
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
} tT1T_INFO;

static tT1T_INFO s_t1t_info;

static void reset_t1t_info() {
    // 清除除了uid和hr以外的所有数据
#if IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
    osi_memset_s(s_t1t_info.attr, T1T_MAX_BLOCK_SIZE, 0, T1T_MAX_BLOCK_SIZE);
    osi_memset_s(s_t1t_info.lock_attr, T1T_MAX_BLOCK_SIZE, 0, T1T_MAX_BLOCK_SIZE);
    osi_memset_s(s_t1t_info.mem, T1T_SEGMENT_SIZE, 0, T1T_SEGMENT_SIZE);
    s_t1t_info.attr[0x00] = 0xFF;
    s_t1t_info.attr[0x0D] = 0xFF;
    s_t1t_info.attr[0x0E] = 0xFF;
    s_t1t_info.ndef_flags = 0;
    s_t1t_info.ndef_len = 0;
    s_t1t_info.ndef_max_size = 0;
    s_t1t_info.ndef_len_start = 0;
    s_t1t_info.ndef_value_start = 0;
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
    s_t1t_info.is_ndef_detected = false;
}

/**
 * @brief 发送T1T静态命令
 *
 * @param cmd_code 命令码
 * @param add 地址 b0-b2: byte块在block中的偏移量，b3-b6: block号，b7: 0
 * @param dat 数据
 * @param pp_rsp 响应数据，如果*pp_rsp为NULL，则分配一个buf
 *
 * @return 状态码
 */
static tNCI_STATUS send_static_cmd(uint8_t cmd_code, uint8_t add, uint8_t dat, tNCI_BUF **pp_rsp) {
    NFCLOG_D("send static cmd: %02x, add=0x%02X, dat=%02X", cmd_code, add, dat);
    if (!pp_rsp) {
        NFCLOG_E("pp_rsp is null");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }

    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    tNCI_BUF *cmd = alloc_nci_buf_with_cap(0, T1T_STATIC_CMD_LEN);
    tNCI_BUF *rsp = *pp_rsp;
    if (!rsp) {
        rsp = alloc_nci_buf(0);
    } else {
        reset_nci_buf(rsp);
    }
    if (!cmd || !rsp) {
        NFCLOG_E("alloc nci buf failed");
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto failed;
    }

    UINT8_TO_BUF(cmd, cmd_code);
    UINT8_TO_BUF(cmd, add);
    UINT8_TO_BUF(cmd, dat);
    ARRAY_TO_BUF(cmd, s_t1t_info.uid, T1T_UID_LEN);

    ret = rw_transmit(cmd, rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("nci data channel transmit failed");
        goto failed;
    }

    *pp_rsp = rsp;
    goto cleanup;
failed:
    free_nci_buf(rsp);
    *pp_rsp = NULL;
cleanup:
    free_nci_buf(cmd);
    return ret;
}

static tNCI_STATUS on_connect(tNCI_RW_TAG *p_tag) {
    osi_memset_s(&s_t1t_info, sizeof(tT1T_INFO), 0, sizeof(tT1T_INFO));
    if (!osi_memcpy_s(s_t1t_info.hr, T1T_HR_LEN, p_tag->tech_params[p_tag->index].pa.hr, T1T_HR_LEN)) {
        NFCLOG_E("copy hr failed");
        return NCI_STATUS_EXT_FAILED;
    }
    if (!osi_memcpy_s(s_t1t_info.uid, T1T_UID_LEN, p_tag->uid, T1T_UID_LEN)) {
        NFCLOG_E("copy uid failed");
        return NCI_STATUS_EXT_FAILED;
    }
    s_t1t_info.is_static = (s_t1t_info.hr[0] & 0x0F) == 0x01;
    reset_t1t_info();
    return NCI_STATUS_OK;
}

static tNCI_STATUS on_disconnect() {
    osi_memset_s(&s_t1t_info, sizeof(tT1T_INFO), 0, sizeof(tT1T_INFO));
    return NCI_STATUS_OK;
}

static tNCI_STATUS presence_check() {
    NFCLOG_I("t1t presence check");
    tNCI_BUF *rsp = NULL;
    tNCI_STATUS ret = send_static_cmd(T1T_CMD_RID, 0x00, 0x00, &rsp);

    if (ret != NCI_STATUS_OK || rsp == NULL) {
        NFCLOG_E("send static cmd failed");
        goto cleanup;
    }

    if (rsp->len < (T1T_HR_LEN + T1T_UID_LEN)) {
        NFCLOG_E("rsp len too short: %d", rsp->len);
        ret = NCI_STATUS_EXT_FAILED;
    }

    if (memcmp(rsp->data, s_t1t_info.hr, T1T_HR_LEN) == 0 && memcmp(rsp->data + T1T_HR_LEN, s_t1t_info.uid, T1T_UID_LEN) == 0) {
        NFCLOG_I("t1t presence check success");
        ret = NCI_STATUS_OK;
    } else {
        NFCLOG_E("t1t presence check failed");
        ret = NCI_STATUS_EXT_FAILED;
    }
cleanup:
    free_nci_buf(rsp);
    return ret;
}

static tNCI_STATUS check_transceive_resp(uint8_t *p_rsp, uint16_t *p_rsp_len) {
    if (!p_rsp || !p_rsp_len || *p_rsp_len < 2) {
        NFCLOG_E("invalid param");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    uint16_t rsp_len = *p_rsp_len;
    if (p_rsp[rsp_len - 1] != 0x00) {
        NFCLOG_E("t1t transceive failed, status=0x%02X", p_rsp[rsp_len - 1]);
        return NCI_STATUS_EXT_FAILED;
    }
    *p_rsp_len = rsp_len - 1; // 去掉最后一个状态字节
    return NCI_STATUS_OK;
}

#if IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)

/**
 * @brief 发送T1T动态命令
 *
 * @param cmd_code 命令码
 * @param add 地址
 * @param p_dat 数据
 * @param pp_rsp 响应数据，如果*pp_rsp为NULL，则分配一个buf
 *
 * @return 成功返回NCI_STATUS_OK，失败返回错误码
 */
static tNCI_STATUS send_dynamic_cmd(uint8_t cmd_code, uint8_t add, const uint8_t *p_dat, tNCI_BUF **pp_rsp) {
    NFCLOG_D("send dynamic cmd: %02x, add=0x%02X", cmd_code, add);
    if (!pp_rsp) {
        NFCLOG_E("pp_rsp is null");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    tNCI_BUF *cmd = alloc_nci_buf_with_cap(0, T1T_DYNAMIC_CMD_LEN);
    tNCI_BUF *rsp = *pp_rsp;
    if (!rsp) {
        rsp = alloc_nci_buf(0);
    } else {
        reset_nci_buf(rsp);
    }
    if (!cmd || !rsp) {
        NFCLOG_E("alloc nci buf failed");
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto failed;
    }

    UINT8_TO_BUF(cmd, cmd_code);
    UINT8_TO_BUF(cmd, add);
    if (p_dat) {
        ARRAY_TO_BUF(cmd, p_dat, T1T_DYNAMIC_DAT_LEN);
    } else {
        FILL_BUF(cmd, 0, T1T_DYNAMIC_DAT_LEN);
    }
    ARRAY_TO_BUF(cmd, s_t1t_info.uid, T1T_UID_LEN);

    ret = rw_transmit(cmd, rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("nci data channel transmit failed");
        goto failed;
    }

    *pp_rsp = rsp;
    goto cleanup;
failed:
    free_nci_buf(rsp);
    *pp_rsp = NULL;
cleanup:
    free_nci_buf(cmd);
    return ret;
}

static void dump_t1t_info() {
    NFCLOG_I("================= t1t info start =================");
    NFCLOG_I("is_ndef_detected: %d", s_t1t_info.is_ndef_detected);
    NFCLOG_I("is_static: %d", s_t1t_info.is_static);
    NFCLOG_I("hr: 0x%02X%02X", s_t1t_info.hr[0], s_t1t_info.hr[1]);
    NFCLOG_I("uid: 0x%02X%02X%02X%02X", s_t1t_info.uid[0], s_t1t_info.uid[1], s_t1t_info.uid[2], s_t1t_info.uid[3]);
    NFCLOG_I("cc: 0x%02X%02X%02X%02X", s_t1t_info.mem[T1T_CC0_NMN_BYTE], s_t1t_info.mem[T1T_CC1_VNO_BYTE], s_t1t_info.mem[T1T_CC2_TMS_BYTE], s_t1t_info.mem[T1T_CC3_RWA_BYTE]);
    NFCLOG_I("ndef_len_start: %d", s_t1t_info.ndef_len_start);
    NFCLOG_I("ndef_value_start: %d", s_t1t_info.ndef_value_start);
    NFCLOG_I("ndef_len: %d", s_t1t_info.ndef_len);
    NFCLOG_I("ndef_max_size: %d", s_t1t_info.ndef_max_size);
    NFCLOG_I("ndef_flags: %02X", s_t1t_info.ndef_flags);
    char *str_buf = osi_calloc(T1T_MAX_BLOCK_SIZE * 2 + 1);
    bytes_to_hex(s_t1t_info.attr, T1T_MAX_BLOCK_SIZE, str_buf);
    NFCLOG_I("attr: %s", str_buf);
    bytes_to_hex(s_t1t_info.lock_attr, T1T_MAX_BLOCK_SIZE, str_buf);
    NFCLOG_I("lock_attr: %s", str_buf);
    NFCLOG_I("================= t1t info end ===================");

    osi_free(str_buf);
}

static tNCI_STATUS t1t_write_erase(uint8_t byte_offset, uint8_t dat, tNCI_BUF **pp_rsp) {
    uint8_t add = ((byte_offset / T1T_BLOCK_SIZE) << 3) | (byte_offset % T1T_BLOCK_SIZE);
    tNCI_STATUS ret = send_static_cmd(T1T_CMD_WRITE_E, add, dat, pp_rsp);
    if (ret != NCI_STATUS_OK) {
        return ret;
    }
    tNCI_BUF *rsp = *pp_rsp;
    if (!rsp || rsp->len != T1T_WRITE_E_RSP_LEN) {
        NFCLOG_E("invalid response");
        return NCI_STATUS_EXT_FAILED;
    }
    if (rsp->data[1] != dat) {
        NFCLOG_E("write data failed, data: %02x", rsp->data[1]);
        return NCI_STATUS_EXT_FAILED;
    }
    return NCI_STATUS_OK;
}

static tNCI_STATUS t1t_write_erase8(uint8_t block_no, const uint8_t *p_dat, tNCI_BUF **pp_rsp) {
    tNCI_STATUS ret = send_dynamic_cmd(T1T_CMD_WRITE_E8, block_no, p_dat, pp_rsp);
    if (ret != NCI_STATUS_OK) {
        return ret;
    }
    tNCI_BUF *rsp = *pp_rsp;
    if (!rsp || rsp->len != T1T_WRITE_E8_RSP_LEN) {
        NFCLOG_E("invalid response");
        return NCI_STATUS_EXT_FAILED;
    }
    if (memcmp(rsp->data + 1, p_dat, T1T_WRITE_E8_RSP_LEN - 2) != 0) {
        NFCLOG_E("write data failed");
        return NCI_STATUS_EXT_FAILED;
    }
    return NCI_STATUS_OK;
}

static tNCI_STATUS t1t_read_8bytes(uint8_t add8, uint8_t *p_out, tNCI_BUF **pp_reuse_rsp) {
    if (!p_out) {
        NFCLOG_E("invalid parameter");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    tNCI_STATUS ret = send_dynamic_cmd(T1T_CMD_READ8, add8, NULL, pp_reuse_rsp);
    if (ret != NCI_STATUS_OK) {
        return ret;
    }
    tNCI_BUF *rsp = *pp_reuse_rsp;
    if (!rsp || rsp->len != T1T_READ8_RSP_LEN) {
        NFCLOG_E("invalid response");
        return NCI_STATUS_EXT_FAILED;
    }
    if (!osi_memcpy_s(p_out, T1T_BLOCK_SIZE, rsp->data + 1, T1T_BLOCK_SIZE)) {
        NFCLOG_E("copy data failed");
        return NCI_STATUS_EXT_COPY_FAILED;
    }
    return NCI_STATUS_OK;
}

static bool is_lock_reserved_opt_byte(uint16_t index) {
    return (s_t1t_info.attr[index / T1T_BLOCK_SIZE] & s_t1t_mask_bits[index % T1T_BLOCK_SIZE]) != 0;
}

/*
static bool is_read_only_byte(uint16_t index) {
    return (s_t1t_info.lock_attr[index / T1T_BLOCK_SIZE] & s_t1t_mask_bits[index % T1T_BLOCK_SIZE]) != 0;
}
*/

static void mark_lock_reserved_opt_byte(uint16_t index) {
    s_t1t_info.attr[index / T1T_BLOCK_SIZE] |= s_t1t_mask_bits[index % T1T_BLOCK_SIZE];
}

static uint8_t calcuate_lock_reserved_opt_byte_count_in_block(uint8_t block_no) {
    uint8_t attr = s_t1t_info.attr[block_no];
    uint8_t count = 0;
    while (attr) {
        attr = attr & (attr - 1);
        count++;
    }
    return count;
}

#define MOVE_TO_NEXT_BYTE(_index, _max_len) \
    _index += 1; \
    while (_index < _max_len) { \
        if (!is_lock_reserved_opt_byte(_index)) { \
            break;\
        } \
        _index += 1;\
    }

#define MOVE_TO_NEXT_BYTE_OR_BREAK(_index, _max_len) \
    MOVE_TO_NEXT_BYTE(_index, _max_len); \
    if (_index >= _max_len) { \
        NFCLOG_W("move to next byte failed, index=%d, max_len=%d", _index, _max_len); \
        break; \
    }

static void set_static_lock_attr(uint8_t *p_data) {
    uint8_t num_lock_bits = 8;
    uint8_t block_no = 0;
    for (uint16_t i = T1T_STATIC_LOCK_OFFSET; i < T1T_STATIC_LOCK_OFFSET + T1T_STATIC_LOCK_LEN; i++) {
        for (uint8_t j = 0; j < num_lock_bits; j++) {
            s_t1t_info.lock_attr[block_no] = 0;
            if (p_data[i] & s_t1t_mask_bits[j]) {
                s_t1t_info.lock_attr[block_no] = 0xFF;
            }
            block_no++;
        }
    }
}

static tNCI_STATUS set_dynamic_lock_attr(uint8_t *p_data, uint16_t data_len, uint16_t offset, uint8_t num_lock_bits, uint8_t bytes_locked_pre_lock_bit) {
    s_t1t_info.lock_bit_start = offset;
    s_t1t_info.lock_bits_count = num_lock_bits;
    uint8_t num_lock_bytes = num_lock_bits / 8;
    if (num_lock_bits % 8 != 0) {
        num_lock_bytes++;
    }
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    uint8_t *p_lock_bytes = osi_calloc(num_lock_bytes);
    if (!p_lock_bytes) {
        NFCLOG_E("malloc failed");
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto cleanup;
    }
    if (offset + num_lock_bytes <= data_len) {
        // 当前p_data有足够的数据，直接从p_data中取数据
        if (!osi_memcpy_s(p_lock_bytes, num_lock_bytes, &p_data[offset], num_lock_bytes)) {
            NFCLOG_E("copy lock bytes failed");
            ret = NCI_STATUS_EXT_COPY_FAILED;
            goto cleanup;
        }
    } else {
        // 当前p_data不够，需要继续读取数据
        uint8_t read8[T1T_BLOCK_SIZE] = {};
        tNCI_BUF *rsp = NULL;
        uint8_t read_len = 0;
        while (read_len < num_lock_bytes) {
            ret = t1t_read_8bytes((offset + read_len) / T1T_BLOCK_SIZE, read8, &rsp);
            if (ret != NCI_STATUS_OK) {
                NFCLOG_E("read 8 bytes failed");
                free_nci_buf(rsp);
                goto cleanup;
            }
            uint8_t copy_len = T1T_BLOCK_SIZE;
            if (read_len + copy_len > num_lock_bytes) {
                copy_len = num_lock_bytes - read_len;
            }
            if (!osi_memcpy_s(p_lock_bytes + read_len, copy_len, read8, copy_len)) {
                NFCLOG_E("copy lock bytes failed");
                ret = NCI_STATUS_EXT_COPY_FAILED;
                free_nci_buf(rsp);
                goto cleanup;
            }
        }
        free_nci_buf(rsp);
    }

    uint16_t byte_offst = 0x10 * T1T_BLOCK_SIZE;
    for (uint8_t i = 0; i < num_lock_bytes; i++) {
        uint8_t num_of_bits = 8;
        if (i == (num_lock_bytes - 1)) {
            num_of_bits = ((num_lock_bits % 8) == 0) ? 8 : (num_lock_bits % 8);
        }
        for (uint8_t j = 0; j < num_of_bits; j++) {
            if (p_lock_bytes[i] & s_t1t_mask_bits[j]) {
                // 当前Bit是锁定状态，更新lock_attr
                for (uint8_t k = 0; k < bytes_locked_pre_lock_bit; k++) {
                    uint16_t curr_offset = byte_offst + k;
                    s_t1t_info.lock_attr[curr_offset / T1T_BLOCK_SIZE] |= 0x01 << (curr_offset % T1T_BLOCK_SIZE);
                }
            }
            byte_offst += bytes_locked_pre_lock_bit;
        }
    }
    ret = NCI_STATUS_OK;
cleanup:
    osi_free(p_lock_bytes);
    return ret;
}

static tNCI_STATUS t1t_scan_data() {
    if (s_t1t_info.is_ndef_detected) {
        return NCI_STATUS_OK;
    }
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    tNCI_BUF *rsp = NULL;
    // 先读取第一个segment的数据
    if (s_t1t_info.is_static) {
        ret = send_static_cmd(T1T_CMD_RALL, 0x00, 0x00, &rsp);
    } else {
        ret = send_dynamic_cmd(T1T_CMD_RSEG, 0x00, NULL, &rsp);
    }
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("send cmd failed");
        goto cleanup;
    }
    uint8_t expect_rsp_len = s_t1t_info.is_static ? T1T_RALL_RSP_LEN : T1T_RSEG_RSP_LEN;
    if (!rsp || rsp->len != expect_rsp_len) {
        NFCLOG_E("rsp is invalid, expect_rsp_len=%d", expect_rsp_len);
        ret = NCI_STATUS_EXT_FAILED;
        goto cleanup;
    }
    uint8_t data_offset = s_t1t_info.is_static ? 2 : 1; // RALL指令前2byte是HR，RSEG指令前1byte是ADDS
    uint8_t *p_data = rsp->data + data_offset;
    uint16_t data_len = rsp->len - data_offset;

    tT1T_INFO *p_t1t = &s_t1t_info;

    // 保存第一个segment的数据
    if (!osi_memcpy_s(p_t1t->mem, T1T_SEGMENT_SIZE, p_data, data_len)) {
        NFCLOG_E("copy mem failed");
        ret = NCI_STATUS_EXT_COPY_FAILED;
        goto cleanup;
    }

    // 设置静态锁属性
    set_static_lock_attr(p_data);

    // 开始解析tlv
    uint8_t i = T1T_CC_OFFSET + T1T_CC_LEN - 1;
    while (i < data_len) {
        MOVE_TO_NEXT_BYTE_OR_BREAK(i, data_len);
        uint8_t tag = p_data[i];
        if (tag == T1T_TLV_NULL) {
            // NULL TLV，可能只是用于内存对齐，忽略
            continue;
        } else if (tag == T1T_TLV_TERM) {
            // 结束TLV，跳出循环
            break;
        }
        MOVE_TO_NEXT_BYTE_OR_BREAK(i, data_len);
        uint16_t v_len = p_data[i];
        if (tag == T1T_TLV_NDEF) {
            // 保存NDEF LEN的起始位置
            p_t1t->ndef_len_start = i;
        }
        if (v_len == 0xFF) {
            // 长度为0xFF，表示后续两个字节表示长度
            MOVE_TO_NEXT_BYTE_OR_BREAK(i, data_len);
            v_len = p_data[i] << 8;
            MOVE_TO_NEXT_BYTE_OR_BREAK(i, data_len);
            v_len |= p_data[i];
        }
        if (tag == T1T_TLV_NDEF) {
            // 保存NDEF LEN和NDEF VALUE的起始位置
            MOVE_TO_NEXT_BYTE_OR_BREAK(i, data_len);
            p_t1t->ndef_len = v_len;
            p_t1t->ndef_value_start = i;
            break;
        } else if (tag == T1T_TLV_LOCK) {
            // LOCK TLV
            MOVE_TO_NEXT_BYTE_OR_BREAK(i, data_len);
            uint8_t page_addr = (p_data[i] >> 4) & 0x0F;
            uint8_t byte_offset = p_data[i] & 0x0F;
            MOVE_TO_NEXT_BYTE_OR_BREAK(i, data_len);
            uint8_t lock_bit_size = p_data[i];
            MOVE_TO_NEXT_BYTE_OR_BREAK(i, data_len);
            uint8_t bytes_pre_page = p_data[i] & 0x0F;
            uint8_t bytes_locked_pre_lock_bit = (p_data[i] >> 4) & 0x0F;

            uint16_t offset = (page_addr << bytes_pre_page) + byte_offset;
            uint8_t lock_byte_size = lock_bit_size / 8;
            if (lock_bit_size % 8 != 0) {
                lock_byte_size++;
            }
            // 将lock bit所在byte标记为到attr中
            for (uint8_t j = 0; j < lock_byte_size; j++) {
                mark_lock_reserved_opt_byte(offset + j);
            }
            // 设置lock_attr属性
            ret = set_dynamic_lock_attr(p_data, data_len, offset, lock_bit_size, 0x01 << bytes_locked_pre_lock_bit);
            if (ret != NCI_STATUS_OK) {
                NFCLOG_E("set dynamic lock attr failed");
                goto cleanup;
            }
        } else if (tag == T1T_TLV_MEM) {
            // MEM TLV
            MOVE_TO_NEXT_BYTE_OR_BREAK(i, data_len);
            uint8_t page_addr = (p_data[i] >> 4) & 0x0F;
            uint8_t byte_offset = p_data[i] & 0x0F;
            MOVE_TO_NEXT_BYTE_OR_BREAK(i, data_len);
            uint8_t reserved_size = p_data[i];
            MOVE_TO_NEXT_BYTE_OR_BREAK(i, data_len);
            uint8_t bytes_pre_page = p_data[i] & 0x0F;

            uint16_t offset = (page_addr << bytes_pre_page) + byte_offset;
            // 将reserved byte标记为到attr中
            for (uint8_t j = 0; j < reserved_size; j++) {
                mark_lock_reserved_opt_byte(offset + j);
            }
        } else {
            // 未知的TLV，跳过
            NFCLOG_W("unknown tag = 0x%02X, len=%d", tag, v_len);
            while (v_len) {
                MOVE_TO_NEXT_BYTE_OR_BREAK(i, data_len);
                v_len--;
            }
        }
    }

    // 计算ndef max size
    if (p_t1t->ndef_len_start > 0) {
        uint16_t ndef_max_size = 0;
        uint16_t byte_offset = p_t1t->ndef_len_start;
        uint16_t max_size = (p_t1t->mem[T1T_CC2_TMS_BYTE] + 1) << 3;
        while (byte_offset < max_size) {
            // 每一次循环计算一个block中可以写入ndef数据的大小
            uint8_t byte_offset_in_block = byte_offset % T1T_BLOCK_SIZE;
            uint8_t block_no = byte_offset / T1T_BLOCK_SIZE;
            byte_offset = (block_no + 1) << 3; // 指向下一个block起始地址
            if (byte_offset_in_block == 0) {
                if (p_t1t->attr[block_no] == 0xFF) {
                    // 此block中所有byte全部是lock、reserved、opt数据，不可以用于存放ndef数据
                    continue;
                }
                if (p_t1t->lock_attr[block_no] == 0) {
                    // 此block中没有只读byte，那可以写入ndef数据的byte数量就是T1T_BLOCK_SIZE-不可写入ndef数据byte数量
                    ndef_max_size += T1T_BLOCK_SIZE - calcuate_lock_reserved_opt_byte_count_in_block(block_no);
                    continue;
                }
            }
            for (uint8_t i = byte_offset_in_block; i < T1T_BLOCK_SIZE; i++) {
                if (p_t1t->attr[block_no] & s_t1t_mask_bits[i]) {
                    // 此byte是lock、reserved、opt数据，不可以用于存放ndef数据
                    continue;
                } else if (p_t1t->lock_attr[block_no] & s_t1t_mask_bits[i]) {
                    // 此byte是只读数据，不可以用于存放ndef数据, 且此byte不是lock、reserved、opt数据
                    // 后续在写NDEF数据时，写入此byte必定会失败，因此到此为止，前面统计到的长度就是ndef最大可写长度
                    // 直接跳出循环
                    goto ndef_max_len_detection_end;
                } else {
                    // 正常可读写可以存储ndef数据的byte
                    ndef_max_size++;
                }
            }
        }
ndef_max_len_detection_end:
        // 减去len的长度
        if (ndef_max_size > 0xFF) {
            ndef_max_size -= 3;
        } else if (ndef_max_size > 0) {
            ndef_max_size -= 1;
        }
        p_t1t->ndef_max_size = ndef_max_size;
    }

    // 计算ndef flags
    uint8_t flags = 0;
    if ((p_t1t->hr[0] & 0xF0) == T1T_NDEF_SUPPORED) {
        flags |= NCI_RW_NDEF_FL_SUPPORTED;
    }
    if (p_t1t->hr[0] == T1T_IS_TOPAZ96 || p_t1t->hr[0] == T1T_IS_TOPAZ512) {
        flags |= NCI_RW_NDEF_FL_FORMATABLE;
    }
    if (((p_t1t->mem[T1T_CC3_RWA_BYTE] & 0x0F) == T1T_CC_RWA_RO) || p_t1t->ndef_max_size < p_t1t->ndef_len) {
        flags |= NCI_RW_NDEF_FL_READ_ONLY;
    }
    if ((flags & NCI_RW_NDEF_FL_READ_ONLY) == 0) {
        flags |= NCI_RW_NDEF_FL_SOFT_LOCKABLE;
    }
    flags |= NCI_RW_NDEF_FL_HARD_LOCKABLE;
    p_t1t->ndef_flags = flags;

    // 设置标记位
    p_t1t->is_ndef_detected = true;

    dump_t1t_info();
cleanup:
    free_nci_buf(rsp);
    return ret;

}

static tNCI_STATUS ndef_detect(tNCI_RW_NDEF_INFO *p_ndef_info) {
    tT1T_INFO *p_t1t = &s_t1t_info;
    if ((p_t1t->hr[0] & 0xF0) != T1T_NDEF_SUPPORED) {
        NFCLOG_I("ndef not supported");
        return NCI_STATUS_EXT_NOT_SUPPORTED;
    }
    reset_t1t_info();
    tNCI_STATUS ret = t1t_scan_data();
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("scan t1t data failed");
        return ret;
    }
    dump_t1t_info();
    if (p_t1t->mem[T1T_CC0_NMN_BYTE] != T1T_CC_MAGIC_NUM) {
        NFCLOG_E("invalid cc nmn: 0x%02X", p_t1t->mem[T1T_CC0_NMN_BYTE]);
        return NCI_STATUS_EXT_NOT_SUPPORTED;
    }
    if (p_t1t->ndef_value_start > 0) {
        p_ndef_info->curr_size = p_t1t->ndef_len;
        p_ndef_info->max_size = p_t1t->ndef_max_size;
        if (p_t1t->ndef_flags & NCI_RW_NDEF_FL_READ_ONLY) {
            p_ndef_info->mode = NCI_RW_NDEF_MODE_READ_ONLY;
        } else {
            p_ndef_info->mode = NCI_RW_NDEF_MODE_READ_WRITE;
        }
        return NCI_STATUS_OK;
    }
    return NCI_STATUS_EXT_NOT_SUPPORTED;
}

static tNCI_STATUS ndef_read(tNCI_RSP *p_rsp) {
    if (!p_rsp) {
        NFCLOG_E("p_rsp is NULL");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    tNCI_STATUS ret = t1t_scan_data();
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("scan t1t data failed");
        return ret;
    }
    tT1T_INFO *p_t1t = &s_t1t_info;
    if (p_t1t->ndef_value_start == 0) {
        NFCLOG_E("ndef not found");
        return NCI_STATUS_EXT_FAILED;
    }

    if (p_t1t->ndef_len == 0) {
        p_rsp->len = 0;
        NFCLOG_I("empty ndef message");
        return NCI_STATUS_EXT_EMPTY_DATA;
    }

    tNCI_BUF *rsp = NULL;
    uint16_t ndef_len = p_t1t->ndef_len;

    p_rsp->data = osi_calloc(ndef_len);
    if (!p_rsp->data) {
        NFCLOG_E("malloc failed");
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto cleanup;
    }
    p_rsp->len = 0;

    uint16_t first_segment_max_size = p_t1t->is_static ? T1T_STATIC_MAX_SIZE : T1T_SEGMENT_SIZE;
    uint16_t byte_offset = p_t1t->ndef_value_start;
    // 先读取第一个segment中的数据
    while (p_rsp->len < ndef_len && byte_offset < first_segment_max_size) {
        if (!is_lock_reserved_opt_byte(byte_offset)) {
            p_rsp->data[p_rsp->len++] = p_t1t->mem[byte_offset];
        }
        byte_offset++;
    }
    if (p_rsp->len == ndef_len) {
        // 所有NDEF数据都已经读取完成
        ret = NCI_STATUS_OK;
        goto cleanup;
    }
    if (p_t1t->is_static) {
        // 静态标签，没有后续segment，判定为读取失败
        NFCLOG_E("read ndef failed, the length already read is %d, the expected length is %d", p_rsp->len, ndef_len);
        ret = NCI_STATUS_EXT_FAILED;
        goto cleanup;
    }

    // 动态标签，需要继续读取后续Segment中的数据
    byte_offset = first_segment_max_size;
    uint16_t t1t_max_size = (p_t1t->mem[T1T_CC2_TMS_BYTE] + 1) << 3;
    while (byte_offset < t1t_max_size && p_rsp->len < ndef_len) {
        uint16_t remain_size = ndef_len - p_rsp->len;
        uint8_t expect_rsp_len = 0;
        uint8_t read_data_len = 0;
        if (remain_size > T1T_BLOCK_SIZE) {
            // 剩余ndef数据大于一个block，直接读取segment
            uint8_t segment_no = (byte_offset / T1T_SEGMENT_SIZE) << 4;
            expect_rsp_len = T1T_RSEG_RSP_LEN;
            read_data_len = T1T_SEGMENT_SIZE;
            ret = send_dynamic_cmd(T1T_CMD_RSEG, segment_no, NULL, &rsp);
        } else {
            // 剩余ndef数据小于一个block，读取block
            uint8_t block_no = byte_offset / T1T_BLOCK_SIZE;
            expect_rsp_len = T1T_READ8_RSP_LEN;
            read_data_len = T1T_BLOCK_SIZE;
            ret = send_dynamic_cmd(T1T_CMD_READ8, block_no, NULL, &rsp);
        }
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("read ndef failed, ret = %d", ret);
            goto cleanup;
        }
        if (rsp->len != expect_rsp_len) {
            NFCLOG_E("read ndef failed, rsp len = %d", rsp->len);
            ret = NCI_STATUS_EXT_FAILED;
            goto cleanup;
        }
        // 将读取到的数据中非保留字节的数据拷贝到ndef中
        uint8_t *p_data = rsp->data + 1;
        for (uint8_t i = 0; i < read_data_len && p_rsp->len < ndef_len; i++) {
            if (!is_lock_reserved_opt_byte(byte_offset)) {
                p_rsp->data[p_rsp->len++] = p_data[i];
            }
            byte_offset++;
        }
    }

    if (p_rsp->len != ndef_len) {
        NFCLOG_E("read ndef failed, the length already read is %d, the expected length is %d", p_rsp->len, ndef_len);
        ret = NCI_STATUS_EXT_FAILED;
        goto cleanup;
    }

    ret = NCI_STATUS_OK;

cleanup:
    free_nci_buf(rsp);
    if (ret != NCI_STATUS_OK) {
        if (p_rsp->data) {
            osi_free(p_rsp->data);
        }
        p_rsp->len = 0;
    }
    return ret;
}

static tNCI_STATUS ndef_format() {
    tNCI_STATUS ret = t1t_scan_data();
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("scan t1t data failed");
        return ret;
    }

    tT1T_INFO *p_t1t = &s_t1t_info;
    tNCI_BUF *rsp = NULL;
    const uint8_t *format_data = s_t1t_info.is_static ? s_t1t_init_data_static : s_t1t_init_data_dynamic;
    uint16_t format_data_len = s_t1t_info.is_static ? sizeof(s_t1t_init_data_static) : sizeof(s_t1t_init_data_dynamic);

    uint16_t write_len = 0;
    while (write_len < format_data_len) {
        uint8_t block_no = (write_len + T1T_CC_OFFSET) / T1T_BLOCK_SIZE;
        if (p_t1t->is_static) {
            ret = t1t_write_erase(write_len + T1T_CC_OFFSET, format_data[write_len], &rsp);
            if (ret != NCI_STATUS_OK) {
                NFCLOG_E("write failed, ret=%d", ret);
                goto cleanup;
            }
            write_len++;
        } else {
            uint8_t curr_write_len = format_data_len - write_len;
            if (curr_write_len < T1T_BLOCK_SIZE) {
                uint8_t write_buf[T1T_BLOCK_SIZE] = {};
                if (!osi_memcpy_s(write_buf, T1T_BLOCK_SIZE, &format_data[write_len], curr_write_len)) {
                    NFCLOG_E("copy write buf failed");
                    ret = NCI_STATUS_EXT_COPY_FAILED;
                    goto cleanup;
                }
                ret = t1t_write_erase8(block_no,(const uint8_t*) write_buf, &rsp);
            } else {
                curr_write_len = T1T_BLOCK_SIZE;
                ret = t1t_write_erase8(block_no, &format_data[write_len], &rsp);
            }
            if (ret != NCI_STATUS_OK) {
                NFCLOG_E("write failed, ret=%d", ret);
                goto cleanup;
            }
            write_len += curr_write_len;
        }
    }
    ret = NCI_STATUS_OK;
    NFCLOG_I("format success");
cleanup:
    reset_t1t_info(); // CC、Lock、Mem TLV更新了，需要重新扫描T1T结构
    if (ret == NCI_STATUS_OK) {
        ret = t1t_scan_data();
    }
    free_nci_buf(rsp);
    return ret;
}

static tNCI_STATUS ndef_write(uint8_t *p_data, uint32_t len) {
    // 检查Tag是否支持NDEF数据
    if ((s_t1t_info.hr[0] & 0xF0) != T1T_NDEF_SUPPORED) {
        NFCLOG_E("ndef is not supported by the tag");
        return NCI_STATUS_EXT_NOT_SUPPORTED;
    }
    tT1T_INFO *p_t1t = &s_t1t_info;
    if (!p_t1t->is_ndef_detected) {
        NFCLOG_E("NDEF not detected");
        return NCI_STATUS_EXT_FAILED;
    }
    // 检查是否是只读Tag
    NFCLOG_I("cc3: %02x", p_t1t->mem[T1T_CC3_RWA_BYTE]);
    if (p_t1t->mem[T1T_CC3_RWA_BYTE] != T1T_CC_RWA_RW) {
        NFCLOG_E("tag is not writable");
        return NCI_STATUS_EXT_FAILED;
    }
    // 检查NDEF长度是否超出最大值
    if (len > p_t1t->ndef_max_size) {
        NFCLOG_E("cannot write NDEF of size greater than %u", p_t1t->ndef_max_size);
        return NCI_STATUS_EXT_FAILED;
    }

    tNCI_BUF *rsp = NULL;
    uint8_t *p_ndef = NULL;
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;

    // 计算NDEF长度字段占用的字节数
    uint8_t len_byte_num = len > 0xFF ? 3 : 1;
    uint16_t total_len = len + len_byte_num;

    uint8_t ndef_final_block[T1T_BLOCK_SIZE] = {0};
    if (!p_t1t->is_static) {
        // 是动态卡片时，先读最后一个block
        uint16_t ndef_end_position = p_t1t->ndef_len_start;
        uint16_t tmp_offset = 0;
        while (tmp_offset < total_len) {
            if (!is_lock_reserved_opt_byte(ndef_end_position)) {
                tmp_offset++;
            }
            ndef_end_position++;
        }

        uint16_t ndef_end_block = (ndef_end_position - 1) / T1T_BLOCK_SIZE;
        NFCLOG_I("ndef_end_position=%d, tmp_offset=%d, ndef_end_block=%d", ndef_end_position, tmp_offset, ndef_end_block);
        ret = t1t_read_8bytes(ndef_end_block, ndef_final_block, &rsp);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("read ndef final block failed");
            goto cleanup;
        }
    }

    // 先将CC0标记为不支持NDEF
    ret = t1t_write_erase(T1T_CC0_NMN_BYTE, 0, &rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("write cc failed");
        goto cleanup;
    }

    uint16_t byte_offset = p_t1t->ndef_len_start;
    uint8_t ndef_len_offset_in_block = p_t1t->ndef_len_start % T1T_BLOCK_SIZE;
    if (!p_t1t->is_static) {
        // 动态内存的卡片需要从block开头开始写入
        byte_offset = (p_t1t->ndef_len_start / T1T_BLOCK_SIZE) * T1T_BLOCK_SIZE;
        // 动态内存的卡片将LEN所在Block全部加入写入的数据中，方便使用write_e8进行写入
        total_len += ndef_len_offset_in_block;
    }
    // 分配LEN+NDEF数据空间，并将LEN和NDEF数据拷贝到该空间
    p_ndef = osi_calloc(total_len);
    if (!p_ndef) {
        NFCLOG_E("allocate ndef failed");
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto cleanup;
    }
    uint8_t idx = 0;
    if (!p_t1t->is_static) {
        // 将len所在block len之前的数据复制到p_ndef中
        if (!osi_memcpy_s(p_ndef, total_len, p_t1t->mem + byte_offset, ndef_len_offset_in_block)) {
            NFCLOG_E("copy ndef data failed");
            ret = NCI_STATUS_EXT_COPY_FAILED;
            goto cleanup;
        }
        idx += ndef_len_offset_in_block;
    }
    if (len > 0xFF) {
        p_ndef[idx] = 0xFF;
        p_ndef[idx + 1] = (len >> 8) & 0xFF;
        p_ndef[idx + 2] = len & 0xFF;
    } else {
        p_ndef[idx] = (uint8_t) len;
    }
    if (!osi_memcpy_s(p_ndef + len_byte_num + idx, len, p_data, len)) {
        NFCLOG_E("copy ndef data failed");
        ret = NCI_STATUS_EXT_COPY_FAILED;
        goto cleanup;
    }

    // 开始写入NDEF数据
    uint16_t write_len = 0;
    uint16_t max_size = (p_t1t->mem[T1T_CC2_TMS_BYTE] + 1) << 3;
    uint8_t write_buf[T1T_BLOCK_SIZE] = {};

    while (write_len < total_len && byte_offset < max_size) {
        // 每次循环写入一个block
        uint8_t block_no = byte_offset / T1T_BLOCK_SIZE;
        uint16_t remain_len = total_len - write_len;
        uint8_t offset_in_block = byte_offset % T1T_BLOCK_SIZE;
        uint8_t block_attr = p_t1t->attr[block_no];
        byte_offset = (block_no + 1) << 3; // 跳到下一个block起始地址
        if (!p_t1t->is_static && remain_len >= T1T_BLOCK_SIZE && offset_in_block == 0 && block_attr == 0) {
            // 同时满足以下条件时，一次性写入一个Block：
            // 1.tag支持动态内存结构
            // 2.剩余数据大于一个Block
            // 3.byte_offset在block起始位置
            // 4.当前block的所有byte都是可写状态
            ret = t1t_write_erase8(block_no, (const uint8_t*)(p_ndef + write_len), &rsp);
            if (ret != NCI_STATUS_OK) {
                NFCLOG_E("write ndef failed, ret=%d", ret);
                goto cleanup;
            }
            write_len += T1T_BLOCK_SIZE;
            // byte_offset += T1T_BLOCK_SIZE;
        } else if (offset_in_block == 0 && block_attr == 0xFF) {
            // byte_offset在Block起始位置且当前Block的所有byte都是不可写状态，跳过这个block
            // byte_offset += T1T_BLOCK_SIZE;
            continue;
        } else if (!p_t1t->is_static && block_no > T1T_STATIC_MAX_BLCOK_COUNT) {
            // 当前已经超过静态区域，无法单byte写入
            if (!osi_memcpy_s(write_buf, T1T_BLOCK_SIZE, ndef_final_block, T1T_BLOCK_SIZE)) {
                NFCLOG_E("copy write buf failed");
                ret = NCI_STATUS_EXT_COPY_FAILED;
                goto cleanup;
            }
            for (uint8_t i = offset_in_block; i < T1T_BLOCK_SIZE && write_len < total_len; i++) {
                if (block_attr & s_t1t_mask_bits[i]) {
                    // 此byte不能存储NDEF数据，跳过
                    continue;
                }
                write_buf[i] = p_ndef[write_len];
                write_len++;
            }
            ret = t1t_write_erase8(block_no, write_buf, &rsp);
            if (ret != NCI_STATUS_OK) {
                NFCLOG_E("write block failed, ret=%d", ret);
                goto cleanup;
            }
        } else {
            // 当block_no还处于静态内存范围内时，需要一个byte一个byte的写入的场景：
            // 1.tag不支持动态内存结构
            // 2.当前Block的某些byte不能写入NDEF数据
            // 3.剩余数据小于一个Block
            // 4.offset_in_block不等于0
            for (uint8_t i = offset_in_block; i < T1T_BLOCK_SIZE && write_len < total_len; i++) {
                if (block_attr & s_t1t_mask_bits[i]) {
                    // 此byte不能存储NDEF数据，跳过
                    continue;
                }
                ret = t1t_write_erase((block_no << 3) + i, p_ndef[write_len], &rsp);
                if (ret != NCI_STATUS_OK) {
                    NFCLOG_E("write ndef failed, ret=%d", ret);
                    goto cleanup;
                }
                write_len++;
            }
        }
    }
    // 校验写入的数据长度是否正确
    if (write_len != total_len) {
        NFCLOG_E("write ndef failed, write_len=%d, total_len=%d", write_len, total_len);
        ret = NCI_STATUS_EXT_FAILED;
        goto cleanup;
    }
    // 最后将CC0标记为支持NDEF
    ret = t1t_write_erase(T1T_CC0_NMN_BYTE, T1T_CC_MAGIC_NUM, &rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("write cc0 failed, ret=%d", ret);
        goto cleanup;
    }

cleanup:
    free_nci_buf(rsp);
    if (p_ndef) {
        osi_free(p_ndef);
    }
    // 重新写入了ndef数据，需要重新扫描T1T数据
    reset_t1t_info();
    return ret;
}

static tNCI_STATUS is_ndef_formatable() {
    return NCI_STATUS_OK;
}

static tNCI_STATUS set_tag_read_only(bool is_hard_lock) {
    /**
     * 1. 检测NDEF detect状态
     * 2. 写CC RWA Byte为只读，如果是软锁则到此结束，如果是硬锁则继续执行
     * 3. 写Static Lock字节
     * 4. 写Dynamic Lock字节
     */
    tT1T_INFO *p_t1t = &s_t1t_info;
    if (!p_t1t->is_ndef_detected) {
        NFCLOG_E("NDEF not detected");
        return NCI_STATUS_EXT_FAILED;
    }

    tNCI_BUF *rsp = NULL;
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;

    // 设置软锁定
    if ((p_t1t->mem[T1T_CC3_RWA_BYTE] & T1T_CC_RWA_RO) != T1T_CC_RWA_RO) {
        // 写CC RWA Bytes
        ret = send_static_cmd(T1T_CMD_WRITE_NE, T1T_OFFSET_TO_ADD(T1T_CC3_RWA_BYTE), T1T_CC_RWA_RO, &rsp);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("write CC RWA byte failed, ret=%d", ret);
            goto cleanup;
        }
        p_t1t->mem[T1T_CC3_RWA_BYTE] = T1T_CC_RWA_RO;
    }
    if (!is_hard_lock) {
        ret = NCI_STATUS_OK;
        goto cleanup;
    }

    uint8_t block_buf[T1T_BLOCK_SIZE] = {0};

    // 设置硬锁定

    // 写Static Lock Byte
    if (p_t1t->is_static) {
        ret = send_static_cmd(T1T_CMD_WRITE_NE, T1T_OFFSET_TO_ADD(T1T_STATIC_LOCK_OFFSET), 0xFF, &rsp);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("write static lock byte0 failed, ret=%d", ret);
            goto cleanup;
        }
        ret = send_static_cmd(T1T_CMD_WRITE_NE, T1T_OFFSET_TO_ADD(T1T_STATIC_LOCK_OFFSET + 1), 0xFF, &rsp);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("write static lock byte1 failed, ret=%d", ret);
            goto cleanup;
        }
    } else {
        block_buf[0] = 0xFF;
        block_buf[1] = 0xFF;
        ret = send_dynamic_cmd(T1T_CMD_WRITE_NE8, T1T_STATIC_LOCK_BLOCK, block_buf, &rsp);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("write static lock byte failed, ret=%d", ret);
            goto cleanup;
        }
    }
    p_t1t->mem[T1T_STATIC_LOCK_OFFSET] = 0xFF;
    p_t1t->mem[T1T_STATIC_LOCK_OFFSET + 1] = 0xFF;
    // 更新Static Lock Attr为0xFF
    if (!osi_memset_s(p_t1t->lock_attr, T1T_STATIC_MAX_BLCOK_COUNT, 0xFF, T1T_STATIC_MAX_BLCOK_COUNT)) {
        NFCLOG_E("update static lock attr failed");
        ret = NCI_STATUS_EXT_FAILED;
        goto cleanup;
    }

    if (p_t1t->is_static) {
        // 静态卡片，不需要继续设置动态Lock
        ret = NCI_STATUS_OK;
        goto cleanup;
    }

    // 写Dynamic Lock Byte
    uint16_t lock_block_no = p_t1t->lock_bit_start / T1T_BLOCK_SIZE;
    uint8_t lock_block_offset = p_t1t->lock_bit_start % T1T_BLOCK_SIZE;
    uint8_t lock_byte_count = p_t1t->lock_bits_count / 8;
    if (p_t1t->lock_bits_count % 8 != 0) {
        lock_byte_count++;
    }

    uint8_t write_len = 0;
    while (write_len < lock_byte_count) {
        // 每一轮循环写一个block
        if (!osi_memset_s(block_buf, T1T_BLOCK_SIZE, 0, T1T_BLOCK_SIZE)) {
            NFCLOG_E("clear block buf failed");
            ret = NCI_STATUS_EXT_FAILED;
            goto cleanup;
        }

        uint8_t memset_len = lock_byte_count - write_len;
        if (memset_len > (T1T_BLOCK_SIZE - lock_block_offset)) {
            memset_len = T1T_BLOCK_SIZE - lock_block_offset;
        }

        if (!osi_memset_s(block_buf + lock_block_offset, memset_len, 0xFF, memset_len)) {
            NFCLOG_E("set block buf failed");
            ret = NCI_STATUS_EXT_FAILED;
            goto cleanup;
        }

        ret = send_dynamic_cmd(T1T_CMD_WRITE_NE8, lock_block_no, block_buf, &rsp);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("write dynamic lock block failed, ret=%d", ret);
            goto cleanup;
        }

        lock_block_no++;
        lock_block_offset = 0;
        write_len += memset_len;
    }
    if (!osi_memset_s(&p_t1t->lock_attr[T1T_STATIC_MAX_BLCOK_COUNT], T1T_MAX_BLOCK_SIZE - T1T_STATIC_MAX_BLCOK_COUNT, 0xFF, T1T_MAX_BLOCK_SIZE - T1T_STATIC_MAX_BLCOK_COUNT)) {
        NFCLOG_E("update dynamic lock attr failed");
        ret = NCI_STATUS_EXT_FAILED;
        goto cleanup;
    }

cleanup:
    free_nci_buf(rsp);
    return ret;
}

#endif // IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)

tNCI_RW_TAG_API g_rw_t1t_api = {
    .max_retry_count = NCI_RW_DEFAULT_MAX_RETRY_COUNT,
    .on_connect = on_connect,
    .on_disconnect = on_disconnect,
    .presence_check = presence_check,
    .check_transceive_resp = check_transceive_resp,
#if IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
    .ndef_detect = ndef_detect,
    .ndef_read = ndef_read,
    .ndef_format = ndef_format,
    .ndef_write = ndef_write,
    .is_ndef_formatable = is_ndef_formatable,
    .set_tag_read_only = set_tag_read_only,
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
};

#endif // IS_FEATURE_ON(NCI_FEATURE_RW_T1T)

